﻿package main

import (
	"bytes"
	"fmt"
	"strconv"
	"time"

	"github.com/hyperledger/fabric/core/chaincode/lib/cid"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/protos/peer"
	jsoniter "github.com/json-iterator/go"
)

//ContractChaincode 链码结构体
type ContractChaincode struct {
}

//定义Contract结构体
type contract struct {
	Name           string          `json:"name"`
	ContractType   string          `json:"contractType"`
	Code           string          `json:"code"`
	Money          float64         `json:"money"`
	TaxRate        float64         `json:"taxRate"`
	Tax            float64         `json:"tax"`
	AllMoney       float64         `json:"allMoney"`
	Content        string          `json:"content"`
	Status         string          `json:"status"`
	InvalidCause   string          `json:"invalidCause"`
	EffectTime     string          `json:"effectTime"`
	LostEffectTime string          `json:"lostEffectTime"`
	EndTime        string          `json:"endTime"`
	AuditTime      string          `json:"auditTime"`
	Note           string          `json:"note"`
	CreateTime     string          `json:"createTime"`
	IpfsHash       string          `json:"ipfsHash"`
	CreatePerson   person          `json:"createPerson"`
	ContractPartys []contractParty `json:"contractPartys"`
}

//定义ContractParty结构体
type contractParty struct {
	Title           string `json:"title"`
	BusinessType    string `json:"businessType"`
	Business        person `json:"business"`
	IsSign          string `json:"isSign"`
	SignTime        string `json:"signTime"`
	SignUser        person `json:"signUser"`
	InvalidSign     string `json:"invalidSign"`
	InvalidSignTime string `json:"invalidSignTime"`
	InvalidSignUser person `json:"invalidSignUser"`
}

//定义人员结构体
type person struct {
	StandardName     string `json:"standardName"`
	CredentialType   string `json:"credentialType"`
	CredentialNumber string `json:"credentialNumber"`
}

//Init 方法
func (t *ContractChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response {
	return shim.Success(nil)
}

//Invoke 方法
func (t *ContractChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response {

	fn, args := stub.GetFunctionAndParameters()

	if fn == "createContract" {
		return t.createContract(stub, args)
	} else if fn == "updateContract" {
		return t.updateContract(stub, args)
	} else if fn == "upgradeContract" {
		return t.upgradeContract(stub, args)
	} else if fn == "createContractParty" {
		return t.createContractParty(stub, args)
	} else if fn == "deleteContractParty" {
		return t.deleteContractParty(stub, args)
	} else if fn == "signContract" {
		return t.signContract(stub, args)
	} else if fn == "unSignContract" {
		return t.unSignContract(stub, args)
	} else if fn == "invalidSignContract" {
		return t.invalidSignContract(stub, args)
	}

	return shim.Error("chaincodeNotFoundFunction")

}

//创建Contract记录
func (t *ContractChaincode) createContract(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	// 定义json解析器
	var jsoniter = jsoniter.ConfigCompatibleWithStandardLibrary
	dataKey := args[0]
	//判断Contract记录是否存在
	contractAsBytes, err := stub.GetState(dataKey)
	if err != nil {
		return shim.Error("chaincodeRunError")
	}
	// 如果存在了，需要报错
	if contractAsBytes != nil {
		return shim.Error("chaincodeContractDataKeyAlreadyExist")
	}
	contract := contract{}
	contract.Name = args[1]
	contract.ContractType = args[2]
	contract.Code = args[3]
	// 验证Money格式
	_Money, err := strconv.ParseFloat(args[4], 64)
	if err != nil {
		return shim.Error("chaincodeContractMoneyNotFoundOrFormatError")
	}
	contract.Money = _Money
	// 验证TaxRate格式
	_TaxRate, err := strconv.ParseFloat(args[5], 64)
	if err != nil {
		return shim.Error("chaincodeContractTaxRateNotFoundOrFormatError")
	}
	contract.TaxRate = _TaxRate
	// 验证Tax格式
	_Tax, err := strconv.ParseFloat(args[6], 64)
	if err != nil {
		return shim.Error("chaincodeContractTaxNotFoundOrFormatError")
	}
	contract.Tax = _Tax
	// 验证AllMoney格式
	_AllMoney, err := strconv.ParseFloat(args[7], 64)
	if err != nil {
		return shim.Error("chaincodeContractAllMoneyNotFoundOrFormatError")
	}
	contract.AllMoney = _AllMoney

	contract.Content = args[8]
	contract.EffectTime = args[9]
	contract.LostEffectTime = args[10]
	contract.EndTime = args[11]
	contract.AuditTime = args[12]
	contract.Note = args[13]

	contract.Status = "01"
	loc, _ := time.LoadLocation("Asia/Shanghai")
	contract.CreateTime = time.Now().In(loc).Format("2006-01-02 15:04:05")
	contract.CreatePerson = getCaUser(stub)
	contractAsBytes, err = jsoniter.Marshal(&contract)
	if err != nil {
		return shim.Error("chaincodeJsonSerializeError")
	}

	err = stub.PutState(dataKey, contractAsBytes)

	if err != nil {
		return shim.Error("chaincodeRunError")
	}

	var buffer bytes.Buffer
	buffer.WriteString("success")
	return shim.Success(buffer.Bytes())
}

// 修改Contract记录
func (t *ContractChaincode) updateContract(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	// 定义json解析器
	var jsoniter = jsoniter.ConfigCompatibleWithStandardLibrary
	dataKey := args[0]
	// 判断Contract记录是否存在
	contractAsBytes, err := stub.GetState(dataKey)
	if err != nil {
		return shim.Error("chaincodeRunError")
	}
	contract := contract{}
	// 如果不存在了，需要报错
	if contractAsBytes == nil {
		return shim.Error("chaincodeContractNotExist")
	}
	err = jsoniter.Unmarshal(contractAsBytes, &contract)
	if err != nil {
		return shim.Error("chaincodeJsonSerializeError")
	}
	caUser := getCaUser(stub)
	// 判断修改合同的用户，是否为创建合同的用户
	if contract.CreatePerson.CredentialType != caUser.CredentialType || contract.CreatePerson.CredentialNumber != caUser.CredentialNumber {
		return shim.Error("chaincodeContractUpdateNotEntryUser")
	}
	// 验证合同状态是否为草稿，只有合同在草稿状态下才允许修改
	if contract.Status != "01" {
		return shim.Error("chaincodeContractStatusNotDraft")
	}
	contract.Name = args[1]
	contract.ContractType = args[2]
	contract.Code = args[3]
	// 验证Money格式
	_Money, err := strconv.ParseFloat(args[4], 64)
	if err != nil {
		return shim.Error("chaincodeContractMoneyNotFoundOrFormatError")
	}
	contract.Money = _Money
	// 验证TaxRate格式
	_TaxRate, err := strconv.ParseFloat(args[5], 64)
	if err != nil {
		return shim.Error("chaincodeContractTaxRateNotFoundOrFormatError")
	}
	contract.TaxRate = _TaxRate
	// 验证Tax格式
	_Tax, err := strconv.ParseFloat(args[6], 64)
	if err != nil {
		return shim.Error("chaincodeContractTaxNotFoundOrFormatError")
	}
	contract.Tax = _Tax
	// 验证AllMoney格式
	_AllMoney, err := strconv.ParseFloat(args[7], 64)
	if err != nil {
		return shim.Error("chaincodeContractAllMoneyNotFoundOrFormatError")
	}
	contract.AllMoney = _AllMoney

	contract.Content = args[8]
	contract.EffectTime = args[9]
	contract.LostEffectTime = args[10]
	contract.EndTime = args[11]
	contract.AuditTime = args[12]
	contract.Note = args[13]
	contractAsBytes, err = jsoniter.Marshal(&contract)
	if err != nil {
		return shim.Error("chaincodeJsonSerializeError")
	}

	err = stub.PutState(dataKey, contractAsBytes)
	if err != nil {
		return shim.Error("chaincodeRunError")
	}

	var buffer bytes.Buffer
	buffer.WriteString("success")
	return shim.Success(buffer.Bytes())
}

// 升级Contract记录
func (t *ContractChaincode) upgradeContract(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	// 定义json解析器
	var jsoniter = jsoniter.ConfigCompatibleWithStandardLibrary
	dataKey := args[0]
	// 判断Contract记录是否存在
	contractAsBytes, err := stub.GetState(dataKey)
	if err != nil {
		return shim.Error("chaincodeRunError")
	}
	contract := contract{}
	// 如果不存在了，需要报错
	if contractAsBytes == nil {
		return shim.Error("chaincodeContractNotExist")
	}
	err = jsoniter.Unmarshal(contractAsBytes, &contract)
	if err != nil {
		return shim.Error("chaincodeJsonSerializeError")
	}
	// 判断修改合同的用户，是否为创建合同的用户
	caUser := getCaUser(stub)
	if contract.CreatePerson.CredentialType != caUser.CredentialType || contract.CreatePerson.CredentialNumber != caUser.CredentialNumber {
		return shim.Error("chaincodeContractUpdateNotEntryUser")
	}

	status := args[1]
	invalidCause := args[2]
	// 如果升级待作废，需要填写作废原因
	if status == "06" && invalidCause == "null" {
		return shim.Error("chaincodeContractNotFoundInvalidCause")
	}
	// 验证升级状态是否符合标准
	switch status {
	case "02":
		if contract.Status != "01" {
			return shim.Error("chaincodeContractUpgradeStatusError")
		}
	case "03":
		if contract.Status == "02" {
			// 从会签升级到待生效状态，需要验证合同参与方，是否都已经签字了
			notSignAll := false
			for _, value := range contract.ContractPartys {
				if value.IsSign == "02" {
					notSignAll = true
					break
				}
			}
			if notSignAll {
				return shim.Error("chaincodeContractNotSignAll")
			}
		} else {
			return shim.Error("chaincodeContractUpgradeStatusError")
		}
	case "04":
		if contract.Status == "02" || contract.Status == "03" {
			// 从待生效或者会签升级到履行状态，需要验证合同参与方，是否都已经签字了
			notSignAll := false
			for _, value := range contract.ContractPartys {
				if value.IsSign == "02" {
					notSignAll = true
					break
				}
			}
			if notSignAll {
				return shim.Error("chaincodeContractNotSignAll")
			}
		} else {
			return shim.Error("chaincodeContractUpgradeStatusError")
		}
	case "05":
		if contract.Status != "04" {
			return shim.Error("chaincodeContractUpgradeStatusError")
		}
	case "06":
		if contract.Status != "02" && contract.Status != "03" && contract.Status != "04" {
			return shim.Error("chaincodeContractUpgradeStatusError")
		}
	case "07":
		if contract.Status == "06" {
			// 从待作废升级到作废状态，需要验证合同参与方，是否都已经作废签字了
			notSignAll := false
			for _, value := range contract.ContractPartys {
				if value.InvalidSign == "02" {
					notSignAll = true
					break
				}
			}
			if notSignAll {
				return shim.Error("chaincodeContractNotSignAll")
			}
		} else {
			return shim.Error("chaincodeContractUpgradeStatusError")
		}
	case "08":
		if contract.Status != "03" && contract.Status != "04" {
			return shim.Error("chaincodeContractUpgradeStatusError")
		}
	default:
		return shim.Error("chaincodeContractUpgradeStatusError")
	}
	contract.Status = status
	contract.InvalidCause = invalidCause
	contractAsBytes, err = jsoniter.Marshal(&contract)
	if err != nil {
		return shim.Error("chaincodeJsonSerializeError")
	}

	err = stub.PutState(dataKey, contractAsBytes)
	if err != nil {
		return shim.Error("chaincodeRunError")
	}

	var buffer bytes.Buffer
	buffer.WriteString("success")
	return shim.Success(buffer.Bytes())
}

// 添加合同参与方
func (t *ContractChaincode) createContractParty(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	// 定义json解析器
	var jsoniter = jsoniter.ConfigCompatibleWithStandardLibrary
	dataKey := args[0]
	// 判断Contract记录是否存在
	contractAsBytes, err := stub.GetState(dataKey)
	if err != nil {
		return shim.Error("chaincodeRunError")
	}
	contract := contract{}
	// 如果不存在了，需要报错
	if contractAsBytes == nil {
		return shim.Error("chaincodeContractNotExist")
	}
	err = jsoniter.Unmarshal(contractAsBytes, &contract)
	if err != nil {
		return shim.Error("chaincodeJsonSerializeError")
	}
	// 判断修改合同的用户，是否为创建合同的用户
	caUser := getCaUser(stub)
	if contract.CreatePerson.CredentialType != caUser.CredentialType || contract.CreatePerson.CredentialNumber != caUser.CredentialNumber {
		return shim.Error("chaincodeContractUpdateNotEntryUser")
	}
	// 验证合同状态是否为草稿，只有合同在草稿状态下才允许修改
	if contract.Status != "01" {
		return shim.Error("chaincodeContractStatusNotDraft")
	}
	// 组装合同参与方字段
	contractParty := contractParty{}
	contractParty.BusinessType = args[1]
	// 组装人员类型
	person := person{}
	person.StandardName = args[2]
	person.CredentialType = args[3]
	person.CredentialNumber = args[4]

	contractParty.Title = args[5]
	contractParty.IsSign = "02"
	contractParty.InvalidSign = "02"
	contractParty.Business = person
	//添加到合同参与方数组
	contract.ContractPartys = append(contract.ContractPartys, contractParty)

	contractAsBytes, err = jsoniter.Marshal(&contract)
	if err != nil {
		return shim.Error("chaincodeJsonSerializeError")
	}

	err = stub.PutState(dataKey, contractAsBytes)
	if err != nil {
		return shim.Error("chaincodeRunError")
	}

	var buffer bytes.Buffer
	buffer.WriteString("success")
	return shim.Success(buffer.Bytes())
}

// 删除合同参与方
func (t *ContractChaincode) deleteContractParty(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	// 定义json解析器
	var jsoniter = jsoniter.ConfigCompatibleWithStandardLibrary
	dataKey := args[0]
	// 判断Contract记录是否存在
	contractAsBytes, err := stub.GetState(dataKey)
	if err != nil {
		return shim.Error("chaincodeRunError")
	}
	contract := contract{}
	// 如果不存在了，需要报错
	if contractAsBytes == nil {
		return shim.Error("chaincodeContractNotExist")
	}
	err = jsoniter.Unmarshal(contractAsBytes, &contract)
	if err != nil {
		return shim.Error("chaincodeJsonSerializeError")
	}
	// 判断修改合同的用户，是否为创建合同的用户
	caUser := getCaUser(stub)
	if contract.CreatePerson.CredentialType != caUser.CredentialType || contract.CreatePerson.CredentialNumber != caUser.CredentialNumber {
		return shim.Error("chaincodeContractUpdateNotEntryUser")
	}
	// 验证合同状态是否为草稿，只有合同在草稿状态下才允许修改
	if contract.Status != "01" {
		return shim.Error("chaincodeContractStatusNotDraft")
	}

	// 获取用户证件类型和证件号
	credentialType := args[1]
	credentialNumber := args[2]
	// 循环查询合同参与方，按照用户的证件类型和证件号码删除合同参与方
	notExistUser := true
	for key, value := range contract.ContractPartys {
		// 如果发现相同的证件类型和证件号码，从数组中删除合同参与方
		if value.Business.CredentialType == credentialType && value.Business.CredentialNumber == credentialNumber {
			contract.ContractPartys = append(contract.ContractPartys[:key], contract.ContractPartys[key+1:]...)
			notExistUser = false
		}

	}
	// 如果在合同参与方中未发现相应的证件类型和证件号码，报错
	if notExistUser {
		return shim.Error("chaincodeContractPartyUserNotExist")
	}
	contractAsBytes, err = jsoniter.Marshal(&contract)
	if err != nil {
		return shim.Error("chaincodeJsonSerializeError")
	}

	err = stub.PutState(dataKey, contractAsBytes)
	if err != nil {
		return shim.Error("chaincodeRunError")
	}

	var buffer bytes.Buffer
	buffer.WriteString("success")
	return shim.Success(buffer.Bytes())
}

// 合同参与方签字
func (t *ContractChaincode) signContract(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	// 定义json解析器
	var jsoniter = jsoniter.ConfigCompatibleWithStandardLibrary
	dataKey := args[0]
	// 判断Contract记录是否存在
	contractAsBytes, err := stub.GetState(dataKey)
	if err != nil {
		return shim.Error("chaincodeRunError")
	}
	contract := contract{}
	// 如果不存在了，需要报错
	if contractAsBytes == nil {
		return shim.Error("chaincodeContractNotExist")
	}
	err = jsoniter.Unmarshal(contractAsBytes, &contract)
	if err != nil {
		return shim.Error("chaincodeJsonSerializeError")
	}
	// 验证合同状态是否为会签，只有合同在会签状态下才允许签字
	if contract.Status != "02" {
		return shim.Error("chaincodeContractStatusNotCountersign")
	}

	// 获取用户证件类型和证件号
	credentialType := args[1]
	credentialNumber := args[2]
	// 循环查询合同参与方，按照用户的证件类型和证件号码删除合同参与方
	notExistUser := true
	for key, value := range contract.ContractPartys {
		// 如果发现相同的证件类型和证件号码，从数组中删除合同参与方
		if value.Business.CredentialType == credentialType && value.Business.CredentialNumber == credentialNumber {
			_contractPartys := value
			_contractPartys.IsSign = "01"
			// 获取当前时间
			loc, _ := time.LoadLocation("Asia/Shanghai")
			_contractPartys.SignTime = time.Now().In(loc).Format("2006-01-02 15:04:05")
			caUser := getCaUser(stub)
			_contractPartys.SignUser = caUser
			contract.ContractPartys[key] = _contractPartys
			notExistUser = false
		}

	}
	// 如果在合同参与方中未发现相应的证件类型和证件号码，报错
	if notExistUser {
		return shim.Error("chaincodeContractPartyUserNotExist")
	}
	contractAsBytes, err = jsoniter.Marshal(&contract)
	if err != nil {
		return shim.Error("chaincodeJsonSerializeError")
	}
	err = stub.PutState(dataKey, contractAsBytes)
	if err != nil {
		return shim.Error("chaincodeRunError")
	}

	var buffer bytes.Buffer
	buffer.WriteString("success")
	return shim.Success(buffer.Bytes())
}

// 合同参与方签字
func (t *ContractChaincode) unSignContract(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	// 定义json解析器
	var jsoniter = jsoniter.ConfigCompatibleWithStandardLibrary
	dataKey := args[0]
	// 判断Contract记录是否存在
	contractAsBytes, err := stub.GetState(dataKey)
	if err != nil {
		return shim.Error("chaincodeRunError")
	}
	contract := contract{}
	// 如果不存在了，需要报错
	if contractAsBytes == nil {
		return shim.Error("chaincodeContractNotExist")
	}
	err = jsoniter.Unmarshal(contractAsBytes, &contract)
	if err != nil {
		return shim.Error("chaincodeJsonSerializeError")
	}
	// 验证合同状态是否为会签，只有合同在会签状态下才允许签字
	if contract.Status != "02" {
		return shim.Error("chaincodeContractStatusNotCountersign")
	}

	// 获取用户证件类型和证件号
	credentialType := args[1]
	credentialNumber := args[2]
	// 循环查询合同参与方，按照用户的证件类型和证件号码删除合同参与方
	notExistUser := true
	for key, value := range contract.ContractPartys {
		// 如果发现相同的证件类型和证件号码，从数组中删除合同参与方
		if value.Business.CredentialType == credentialType && value.Business.CredentialNumber == credentialNumber {
			_contractPartys := value
			_contractPartys.IsSign = "02"
			// 获取当前时间
			loc, _ := time.LoadLocation("Asia/Shanghai")
			_contractPartys.SignTime = time.Now().In(loc).Format("2006-01-02 15:04:05")
			caUser := getCaUser(stub)
			_contractPartys.SignUser = caUser
			contract.ContractPartys[key] = _contractPartys
			notExistUser = false
		}

	}
	// 如果在合同参与方中未发现相应的证件类型和证件号码，报错
	if notExistUser {
		return shim.Error("chaincodeContractPartyUserNotExist")
	}
	contractAsBytes, err = jsoniter.Marshal(&contract)
	if err != nil {
		return shim.Error("chaincodeJsonSerializeError")
	}
	err = stub.PutState(dataKey, contractAsBytes)
	if err != nil {
		return shim.Error("chaincodeRunError")
	}
	var buffer bytes.Buffer
	buffer.WriteString("success")
	return shim.Success(buffer.Bytes())
}

// 合同参与方作废签字
func (t *ContractChaincode) invalidSignContract(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	// 定义json解析器
	var jsoniter = jsoniter.ConfigCompatibleWithStandardLibrary
	dataKey := args[0]
	// 判断Contract记录是否存在
	contractAsBytes, err := stub.GetState(dataKey)
	if err != nil {
		return shim.Error("chaincodeRunError")
	}
	contract := contract{}
	// 如果不存在了，需要报错
	if contractAsBytes == nil {
		return shim.Error("chaincodeContractNotExist")
	}
	err = jsoniter.Unmarshal(contractAsBytes, &contract)
	if err != nil {
		return shim.Error("chaincodeJsonSerializeError")
	}
	// 验证合同状态是否为待作废，只有合同在待作废状态下才允许签字
	if contract.Status != "06" {
		return shim.Error("chaincodeContractStatusNotAwaitInvalid")
	}

	// 获取用户证件类型和证件号
	credentialType := args[1]
	credentialNumber := args[2]
	// 循环查询合同参与方，按照用户的证件类型和证件号码删除合同参与方
	notExistUser := true
	for key, value := range contract.ContractPartys {
		// 如果发现相同的证件类型和证件号码，从数组中删除合同参与方
		if value.Business.CredentialType == credentialType && value.Business.CredentialNumber == credentialNumber {
			_contractPartys := value
			_contractPartys.InvalidSign = "01"
			// 获取当前时间
			loc, _ := time.LoadLocation("Asia/Shanghai")
			_contractPartys.InvalidSignTime = time.Now().In(loc).Format("2006-01-02 15:04:05")
			caUser := getCaUser(stub)
			_contractPartys.InvalidSignUser = caUser
			contract.ContractPartys[key] = _contractPartys
			notExistUser = false
		}
	}
	// 如果在合同参与方中未发现相应的证件类型和证件号码，报错
	if notExistUser {
		return shim.Error("chaincodeContractPartyUserNotExist")
	}
	contractAsBytes, err = jsoniter.Marshal(&contract)
	if err != nil {
		return shim.Error("chaincodeJsonSerializeError")
	}

	err = stub.PutState(dataKey, contractAsBytes)
	if err != nil {
		return shim.Error("chaincodeRunError")
	}
	var buffer bytes.Buffer
	buffer.WriteString("success")
	return shim.Success(buffer.Bytes())
}

func getCaUser(stub shim.ChaincodeStubInterface) person {
	person := person{}
	dv, df, err := cid.GetAttributeValue(stub, "standardName")
	if err == nil {
		if df {
			person.StandardName = dv
		}
	}
	dv, df, err = cid.GetAttributeValue(stub, "credentialType")
	if err == nil {
		if df {
			person.CredentialType = dv
		}
	}
	dv, df, err = cid.GetAttributeValue(stub, "credentialNumber")
	if err == nil {
		if df {
			person.CredentialNumber = dv
		}
	}
	// // 参数先写死，以后需要从ca中读取
	// person.StandardName = "张三"
	// person.CredentialType = "02"
	// person.CredentialNumber = "21148"
	return person
}

func main() {

	err := shim.Start(new(ContractChaincode))
	if err != nil {
		fmt.Println("chaincode start error!")
	}
}
